package base.dao;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import app.util.ClassUtil;
import app.util.StringUtil;
import app.util.UUIDUtil;
import base.PageInfo;
import base.category.sys.YesOrNo;

@SuppressWarnings("unchecked")
@Repository
public class HibernateDaoImp<T> implements IHibernateDao<T> {
	
	@Autowired
	private SessionFactory sessionFactory;
	
	private Session getSession() {
		Session session = sessionFactory.getCurrentSession(); //You must add @Transactional into your @Repository
		return session;
	}

	@Override
	public void save(Object object) {
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());    
	        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();  
	        
			for (PropertyDescriptor property : propertyDescriptors) {
				Method setter = property.getWriteMethod();
				if (setter != null && "id".equals(property.getName())) {
					setter.invoke(object, UUIDUtil.getUUID());
				} else if (setter != null && "createTime".equals(property.getName())) {
					setter.invoke(object, new Date());
				} else if (setter != null && "isUse".equals(property.getName())) {
					setter.invoke(object, YesOrNo.YES_INT);
				}
			} 
			
		} catch (Exception e) {
		}
		getSession().save(object);
	}

	@Override
	public void mergeAndUpdate(Object object) {
		ClassMetadata md = sessionFactory.getClassMetadata(object.getClass());
	    String idPropertyName = md.getIdentifierPropertyName();
	    Object id = null;
		try {
			id = getValue(object, idPropertyName);
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		Object entity = getSession().get(object.getClass(), StringUtil.objectToStr(id));
		
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());    
	        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();  
	        
			for (PropertyDescriptor property : propertyDescriptors) {
				Method setter = property.getWriteMethod();
				if (setter != null) {
					if("isUse".equals(property.getName())){
						continue;
					}
					Object value = getValue(object, property.getName())!=null?getValue(object, property.getName()):getValue(entity, property.getName());
					setter.invoke(entity, value);
				}
			} 
		} catch (Exception e) {
		}
		
		getSession().update(entity);
	}
	
	private Object getValue(Object newInstance, String idPropertyName) throws NoSuchFieldException, IllegalAccessException {
		Field declaredField;
		Object id;
		declaredField = newInstance.getClass().getDeclaredField(idPropertyName);
		declaredField.setAccessible(true);
		id = declaredField.get(newInstance);
		return id;
	}

	@Override
	public void del(Object object) {
		getSession().delete(object);
	}

	@Override
	public T queryEntityById(Class<T> className, String id) {
		T t = (T)queryObjectById(className, id);
		return t;
	}

	@Override
	public Object queryObjectById(Class<?> className, String id) {
		Object load = getSession().get(className, id);
        return load;
	}

	@Override
	public List<Map<String, Object>> queryListBySql(String sql) {
		SQLQuery query = getSession().createSQLQuery(sql);
		return ClassUtil.toHumpNamed(query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list());
	}

	@Override
	public List<T> queryListByHql(String hql) {
		Query query = getSession().createQuery(hql);
		return query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
	}

	@Override
	public PageInfo queryPageListBySql(PageInfo pageInfo, String sql) {
		SQLQuery query = getSession().createSQLQuery(sql);
		int size = query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list().size();
		pageInfo.setAllCount(size);//总数
		query.setFirstResult(pageInfo.getStart());
		query.setMaxResults(pageInfo.getPageSize());
		pageInfo.setObjectList(ClassUtil.toHumpNamed(query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list()));
		return pageInfo;
	}

	@Override
	public PageInfo queryPageListByHql(PageInfo pageInfo, String hql) {
		Query query = getSession().createQuery(hql);
		int size = query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list().size();
		pageInfo.setAllCount(size);//总数
		query.setFirstResult(pageInfo.getStart());
		query.setMaxResults(pageInfo.getPageSize());
		pageInfo.setObjectList(ClassUtil.toHumpNamed(query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list()));
		return pageInfo;
	}

	@Override
	public void executeSql(String sql) {
		SQLQuery query = getSession().createSQLQuery(sql);
		query.executeUpdate();
	}

	@Override
	public void executeHql(String hql) {
		Query query = getSession().createQuery(hql);
		query.executeUpdate();
	}

}
